home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / dos6mm.zip / UMASCAN.ASM < prev    next >
Assembly Source File  |  1993-03-31  |  49KB  |  1,063 lines

  1. ;****************************************************************************
  2. ; UMASCAN scans the PC's address space from 640K to 1MB and lists the ROM,
  3. ; RAM, Video RAM, EMS pages, and unused areas that it finds. Its syntax is:
  4. ;
  5. ;       UMASCAN [/M]
  6. ;
  7. ; where /M forces it to run in monochrome mode (useful on laptops). The
  8. ; ROM it reports may be adapter ROM or system ROM. The RAM it reports may
  9. ; be adapter RAM or UMB RAM. Any unused areas it identifies are candidates
  10. ; to be converted to UMBs using DOS's EMM386.EXE driver.
  11. ;****************************************************************************
  12.  
  13. code            segment
  14.                 assume  cs:code,ds:code
  15.                 org     100h
  16. begin:          jmp     main
  17.  
  18. header1         db      "UMASCAN 1.1 Copyright (c) 1993 Jeff Prosise",0
  19. header2         db      "From: PC Magazine DOS 6 Memory Management with "
  20.                 db      "Utilities",0
  21.  
  22. helpmsg         db      "Draws a map profiling the upper memory area and "
  23.                 db      "identifies unused",13,10
  24.                 db      "address space that may be converted to upper memory "
  25.                 db      "blocks.",13,10,13,10
  26.                 db      "UMASCAN [/M]",13,10,13,10
  27.                 db      "  /M  Use monochrome video attributes.",13,10,13,10
  28.                 db      "Run UMASCAN when EMM386.EXE is not loaded to "
  29.                 db      "identify adapter RAM.",13,10,"$"
  30.  
  31. errmsg1         db      "Syntax: UMASCAN [/M]",13,10,"$"
  32.  
  33. map             db      192 dup (32)            ;Upper memory map
  34.  
  35. colors          label   byte                    ;Color video attributes
  36. border_color    db      1Fh
  37. back_color      db      3Fh
  38. fore_color      db      1Fh
  39. rom_color       db      5Bh
  40. ram_color       db      4Fh
  41. video_color     db      2Eh
  42. ems_color       db      3Fh
  43. unk_color       db      7Fh
  44. note_color      db      07h
  45. title_color     db      0Fh
  46. shadow_color    db      07h
  47.  
  48. mono_colors     db      70h,07h,7Fh,0Fh,0Fh,0Fh ;Monochrome attributes
  49.                 db      0Fh,0Fh,07h,0Fh,07h
  50.  
  51. devname         db      "EMMXXXX0"              ;EMM device name
  52. video_segment   dw      0B800h                  ;Current video segment
  53. video_offset    dw      ?                       ;Video buffer start address
  54. line_length     dw      ?                       ;Bytes per video line
  55. maxrow          db      24                      ;Highest row number
  56.  
  57. text1           db      "F000",0
  58. text2           db      "E000",0
  59. text3           db      "D000",0
  60. text4           db      "C000",0
  61. text5           db      "B000",0
  62. text6           db      "A000",0
  63.  
  64. text7           db      0Ah,"0",0Ch,"1",0Eh,"2",10h,"3"
  65.                 db      13h,"4",15h,"5",17h,"6",19h,"7"
  66.                 db      1Ch,"8",1Eh,"9",20h,"A",22h,"B"
  67.                 db      25h,"C",27h,"D",29h,"E",2Bh,"F"
  68.  
  69. text8           db      "       LEGEND        ",0
  70. text9           db      "RRRR",0
  71. text10          db      "++++",0
  72. text11          db      "VVVV",0
  73. text12          db      "EEEE",0
  74. text12x         db      "UUUU",0
  75. text13          db      "ROM",0
  76. text14          db      "RAM",0
  77. text15          db      "Video Buffer",0
  78. text16          db      "EMS Page Frame",0
  79. text17          db      "Unknown",0
  80.  
  81. text18          db      "1. RRRR indicates adapter ROM or system board "
  82.                 db      "ROM.",0
  83. text19          db      "2. ++++ indicates adapter RAM or UMB RAM created by "
  84.                 db      "a 386 memory manager.",0
  85. text20          db      "3. Areas marked UUUU usually contain a mixture of "
  86.                 db      "ROM, RAM, and unused space.",0
  87. text21          db      "   These areas generally should not be converted to "
  88.                 db      "upper memory blocks.",0
  89. text22          db      "4. Unmarked areas may safely be converted to upper "
  90.                 db      "memory blocks.",0
  91.  
  92. text23          db      " Press Esc to exit ",0
  93.  
  94. ;****************************************************************************
  95. ; Procedure MAIN
  96. ;****************************************************************************
  97.  
  98. main            proc    near
  99.                 cld                             ;Clear direction flag
  100.                 mov     si,81h                  ;Point SI to command line
  101.                 call    scanhelp                ;Scan for "/?" switch
  102.                 jnc     main1                   ;Branch if not found
  103.  
  104.                 mov     ah,09h                  ;Display help text and exit
  105.                 mov     dx,offset helpmsg       ;with ERRORLEVEL=0
  106.                 int     21h
  107.                 mov     ax,4C00h
  108.                 int     21h
  109. ;
  110. ; Modify the color palette if a /M switch was included.
  111. ;
  112. main1:          call    findchar                ;Advance to next character
  113.                 jc      main3                   ;Branch if there is none
  114.                 lodsw                           ;Get the next two characters
  115.                 and     ah,0DFh                 ;Capitalize the second one
  116.                 cmp     ax,4D2Fh                ;Error if other than /M
  117.                 je      main2
  118.  
  119.                 mov     ah,9                    ;Display error message
  120.                 mov     dx,offset errmsg1
  121.                 int     21h
  122.                 mov     ax,4C01h                ;Exit with ERRORLEVEL=1
  123.                 int     21h
  124.  
  125. main2:          call    change_colors           ;Change color palette to mono
  126. ;
  127. ; Draw the screen and terminate when a key is pressed.
  128. ;
  129. main3:          call    init_video              ;Initialize video
  130.                 mov     ah,03h                  ;Get the cursor type
  131.                 mov     bh,00h                  ;from the BIOS
  132.                 int     10h
  133.                 push    cx                      ;Save it
  134.                 mov     ah,01h                  ;Hide the cursor
  135.                 mov     ch,20h
  136.                 int     10h
  137.  
  138.                 call    draw_screen             ;Paint the screen
  139.                 call    build_table             ;Build the map table
  140.                 call    draw_map                ;Display the memory map
  141.  
  142. main4:          mov     ah,00h                  ;Pause until Esc is pressed
  143.                 int     16h
  144.                 cmp     al,27
  145.                 jne     main4
  146.  
  147.                 call    clear_screen            ;Clear the screen
  148.                 mov     ah,0Fh                  ;Get the active page number
  149.                 int     10h
  150.                 mov     ah,02h                  ;Home the cursor to the upper
  151.                 mov     dx,0000h                ;left corner of the screen
  152.                 int     10h
  153.                 mov     ah,01h                  ;Make the cursor visible
  154.                 pop     cx                      ;again
  155.                 int     10h
  156.                 mov     ax,4C00h                ;Exit with ERRORLEVEL=0
  157.                 int     21h
  158. main            endp
  159.  
  160. ;****************************************************************************
  161. ; SCANHELP scans the command line for a /? switch. If found, carry returns
  162. ; set and SI contains its offset. If not found, carry returns clear.
  163. ;****************************************************************************
  164.  
  165. scanhelp        proc    near
  166.                 push    si                      ;Save SI
  167. scanloop:       lodsb                           ;Get a character
  168.                 cmp     al,0Dh                  ;Exit if end of line
  169.                 je      scan_exit
  170.                 cmp     al,"?"                  ;Loop if not "?"
  171.                 jne     scanloop
  172.                 cmp     byte ptr [si-2],"/"     ;Loop if not "/"
  173.                 jne     scanloop
  174.  
  175.                 add     sp,2                    ;Clear the stack
  176.                 sub     si,2                    ;Adjust SI
  177.                 stc                             ;Set carry and exit
  178.                 ret
  179.  
  180. scan_exit:      pop     si                      ;Restore SI
  181.                 clc                             ;Clear carry and exit
  182.                 ret
  183. scanhelp        endp
  184.  
  185. ;****************************************************************************
  186. ; FINDCHAR advances SI to the next non-white space character. On return,
  187. ; carry set indicates EOL was encountered; carry clear indicates it was not.
  188. ;****************************************************************************
  189.  
  190. findchar        proc    near
  191.                 lodsb                           ;Get the next character
  192.                 cmp     al,09h                  ;Loop if tab
  193.                 je      findchar
  194.                 cmp     al,20h                  ;Loop if space
  195.                 je      findchar
  196.                 cmp     al,2Ch                  ;Loop if comma
  197.                 je      findchar
  198.                 dec     si                      ;Point SI to the character
  199.                 cmp     al,0Dh                  ;Exit with carry set if end
  200.                 je      eol                     ;of line is reached
  201.  
  202.                 clc                             ;Clear carry and exit
  203.                 ret
  204.  
  205. eol:            stc                             ;Set carry and exit
  206.                 ret
  207. findchar        endp
  208.  
  209. ;****************************************************************************
  210. ; CHANGE_COLORS copies monochrome attribute values to the color table.
  211. ; On entry, both DS and ES must point to the code segment.
  212. ;****************************************************************************
  213.  
  214. change_colors   proc    near
  215.                 mov     si,offset mono_colors
  216.                 mov     di,offset colors
  217.                 mov     cx,11
  218.                 rep     movsb
  219.                 ret
  220. change_colors   endp
  221.  
  222. ;****************************************************************************
  223. ; INIT_VIDEO initializes the variables used by the program's video output
  224. ; routines and makes sure we're in an 80-column text mode.
  225. ;****************************************************************************
  226.  
  227. init_video      proc    near
  228.                 mov     ax,40h                  ;Point ES to the BIOS data
  229.                 mov     es,ax                   ;area
  230.  
  231.                 mov     al,es:[49h]             ;Get video mode in AL
  232.                 cmp     al,0Fh                  ;Branch if it's other than
  233.                 jne     init1                   ;0Fh (EGA mono graphics)
  234.                 mov     ax,0007h                ;Switch to mode 7 (80-column
  235.                 int     10h                     ;monochrome text)
  236.                 jmp     short init2             ;Branch and change colors
  237.  
  238. init1:          cmp     al,7                    ;Branch if it's other than
  239.                 jne     init3                   ;mode 7 (monochrome text)
  240. init2:          mov     ax,cs                   ;Point ES back to the code
  241.                 mov     es,ax                   ;segment
  242.                 call    change_colors           ;Change color palette to mono
  243.                 mov     ax,40h                  ;Point ES back to the BIOS
  244.                 mov     es,ax                   ;data area
  245.                 mov     video_segment,0B000h    ;Change to monochrome segment
  246.                 jmp     short init5             ;Branch past mode check
  247.  
  248. init3:          cmp     al,2                    ;Reset the video mode if the
  249.                 jb      init4                   ;current video mode number
  250.                 cmp     al,3                    ;is less than 2 or greater
  251.                 jbe     init5                   ;than 3
  252. init4:          mov     ax,0003h                ;Switch to mode 3 (80-column
  253.                 int     10h                     ;color text)
  254.  
  255. init5:          mov     ax,es:[4Ah]             ;Get number of columns in AX
  256.                 shl     ax,1                    ;Compute bytes per video line
  257.                 mov     line_length,ax          ;Store it in LINE_LENGTH
  258.  
  259.                 mov     ax,es:[4Eh]             ;Save the starting address
  260.                 mov     video_offset,ax         ;of the video buffer
  261.  
  262.                 mov     ax,1A00h                ;Branch if the system
  263.                 int     10h                     ;contains a VGA video
  264.                 cmp     al,1Ah                  ;adapter
  265.                 je      init6
  266.  
  267.                 mov     ah,12h                  ;Branch if the system does
  268.                 mov     bl,10h                  ;not contain an EGA video
  269.                 int     10h                     ;adapter
  270.                 cmp     bl,10h
  271.                 je      init7
  272.  
  273. init6:          mov     al,es:[84h]             ;Read the highest row number
  274.                 mov     maxrow,al               ;from the BIOS data area
  275. init7:          ret
  276. init_video      endp
  277.  
  278. ;****************************************************************************
  279. ; BUILD_TABLE fills in the MAP array by performing a series of tests to
  280. ; determine what type of video hardware is installed, where physical EMS
  281. ; pages are located, and what regions of upper memory contain RAM and ROM.
  282. ;****************************************************************************
  283.  
  284. build_table     proc    near
  285.                 mov     ax,cs                   ;Point ES to the code
  286.                 mov     es,ax                   ;segment
  287. ;
  288. ; Check for a VGA video adapter and fill in the A000 and B000 segments
  289. ; if a VGA is detected.
  290. ;
  291.                 mov     ax,1A00h                ;Check for a VGA by calling
  292.                 int     10h                     ;function 1A00h in the
  293.                 cmp     al,1Ah                  ;video BIOS
  294.                 jne     check_ega               ;Branch if no VGA
  295.                 mov     di,offset map           ;Fill the first 64 bytes of
  296.                 mov     al,"V"                  ;the MAP array with "V"s
  297.                 mov     cx,64
  298.                 rep     stosb
  299.                 jmp     check_ems               ;Branch to EMS check
  300. ;
  301. ; If there's an EGA installed, fill in the MAP array based on whether the
  302. ; EGA is attached to a monochrome or color monitor and how much video RAM
  303. ; it contains.
  304. ;
  305. check_ega:      mov     ah,12h                  ;Check for an EGA adapter
  306.                 mov     bl,10h                  ;and branch if there's not
  307.                 int     10h                     ;one installed
  308.                 cmp     bl,10h
  309.                 je      check_cga
  310.  
  311.                 mov     ax,40h                  ;Point ES to the BIOS data
  312.                 mov     es,ax                   ;area
  313.                 cmp     byte ptr es:[49h],7     ;Branch if mode number is
  314.                 jne     ega_color               ;other than 7
  315.  
  316.                 mov     ax,cs                   ;Point ES back to the code
  317.                 mov     es,ax                   ;segment
  318.                 mov     di,offset map+32        ;For an EGA attached to a
  319.                 mov     al,"V"                  ;monochrome monitor, fill
  320.                 mov     cx,16                   ;in B000 through B3FF if
  321.                 cmp     bl,0                    ;the EGA contains 64K of
  322.                 jne     ega1                    ;RAM, or B000 through
  323.                 mov     cx,8                    ;B7FF if there's more
  324. ega1:           rep     stosb                   ;than 64K on board
  325.  
  326.                 mov     di,offset map           ;For an EGA attached to a
  327.                 mov     al,"V"                  ;monochrome monitor, fill
  328.                 mov     cx,32                   ;in A000 through A7FF if
  329.                 cmp     bl,0                    ;the EGA contains 64K of
  330.                 jne     ega2                    ;RAM, or A000 through
  331.                 mov     cx,16                   ;AFFF if there's more
  332. ega2:           rep     stosb                   ;than 64K on board
  333.                 jmp     short check_cga         ;Check for a CGA, too
  334.  
  335. ega_color:      mov     ax,cs                   ;Point ES back to the code
  336.                 mov     es,ax                   ;segment
  337.                 mov     di,offset map+48        ;For an EGA attached to a
  338.                 mov     al,"V"                  ;color monitor, fill in
  339.                 mov     cx,16                   ;B800 through BBFF if the
  340.                 cmp     bl,0                    ;EGA contains 64K of RAM,
  341.                 jne     ega3                    ;or B800 through BFFF if
  342.                 mov     cx,8                    ;there's more than 64K
  343. ega3:           rep     stosb                   ;on board
  344.  
  345.                 mov     di,offset map           ;For an EGA attached to a
  346.                 mov     al,"V"                  ;color monitor, fill in
  347.                 mov     cx,32                   ;A000 through A7FF if the
  348.                 cmp     bl,0                    ;EGA contains 64K of RAM,
  349.                 jne     ega4                    ;or A000 through AFFF if
  350.                 mov     cx,16                   ;there's more than 64K
  351. ega4:           rep     stosb                   ;on board
  352. ;
  353. ; Check for a CGA, MDA, or Hercules card and fill the MAP array accordingly.
  354. ;
  355. check_cga:      mov     dx,3D4h                 ;Write a "V" to bytes 48
  356.                 call    test_crtc               ;through 55 of the MAP
  357.                 jc      check_mda               ;array if there's a
  358.                 mov     di,offset map+48        ;CGA installed
  359.                 mov     al,"V"
  360.                 mov     cx,8
  361.                 rep     stosb
  362.  
  363. check_mda:      mov     dx,3B4h                 ;Write a "V" to bytes 32
  364.                 call    test_crtc               ;through 33 of the MAP
  365.                 jc      check_ems               ;array if there's an
  366.                 mov     di,offset map+32        ;MDA installed
  367.                 mov     al,"V"
  368.                 mov     cx,2
  369.                 rep     stosb
  370.  
  371.                 mov     dx,3BAh                 ;Determine if a Hercules
  372.                 in      al,dx                   ;video adapter is installed
  373.                 mov     ah,al                   ;by seeing if bit 7 of the
  374.                 and     ah,80h                  ;CRTC's Status Register
  375.                 mov     cx,8000h                ;changes
  376. hgc1:           in      al,dx
  377.                 and     al,80h
  378.                 cmp     ah,al
  379.                 jne     hgc2                    ;Exit loop if value changed
  380.                 loop    hgc1                    ;Try again if it didn't
  381.                 jmp     short check_ems         ;Branch if test was negative
  382.  
  383. hgc2:           mov     di,offset map+32        ;Fill the entire B000 area
  384.                 mov     al,"V"                  ;of the MAP array with "V"s
  385.                 mov     cx,32                   ;if a Hercules adapter was
  386.                 rep     stosb                   ;detected
  387. ;
  388. ; Check for the presence of an expanded memory manager (EMM) and locate
  389. ; the EMS page frame if an EMM is installed.
  390. ;
  391. check_ems:      mov     ax,3567h                ;See if there is an EMM
  392.                 int     21h                     ;installed by checking
  393.                 mov     di,10                   ;for the string "EMMXXXX0"
  394.                 mov     si,offset devname       ;10 bytes past where the
  395.                 mov     cx,8                    ;interrupt 67h vector
  396.                 repe    cmpsb                   ;points to
  397.                 jne     check_arom              ;Branch if no EMM detected
  398.  
  399.                 mov     ax,cs                   ;Point ES back to the code
  400.                 mov     es,ax                   ;segment
  401.                 mov     ah,40h                  ;Now make sure the EMM
  402.                 int     67h                     ;hardware is present
  403.                 cmp     ah,00h                  ;and operational
  404.                 jne     check_arom              ;Branch if it's not
  405. ;
  406. ; Get EMS page frame information.
  407. ;
  408.                 mov     ah,41h                  ;Determine segment address
  409.                 int     67h                     ;of the EMS page frame by
  410.                 cmp     ah,00h                  ;calling function 41h
  411.                 jne     check_arom
  412.                 cmp     bx,0A000h               ;Branch if page frame is
  413.                 jb      check_arom              ;below A000h
  414.                 sub     bx,0A000h               ;Compute corresponding
  415.                 mov     cl,7                    ;offset into MAP array
  416.                 shr     bx,cl
  417.                 mov     di,offset map
  418.                 add     di,bx
  419.                 mov     al,"E"                  ;Write "E" to 32 consecutive
  420.                 mov     cx,32                   ;blocks to identify the
  421.                 rep     stosb                   ;page frame
  422. ;
  423. ; Check for adapter ROM by inspecting the first two bytes of every 2K
  424. ; block between segments C000 and F400 for an adapter ROM signature.
  425. ;
  426. check_arom:     mov     si,64                   ;SI holds index into MAP
  427.  
  428. arom1:          cmp     byte ptr [si+offset map],20h    ;Skip this block if
  429.                 jne     next_block                      ;already checked
  430.  
  431.                 mov     ax,si                   ;Compute next segment address
  432.                 mov     cl,7                    ;by shifting SI 7 bits left
  433.                 shl     ax,cl                   ;and adding A000h
  434.                 add     ax,0A000h
  435.                 mov     es,ax                   ;Transfer result to ES
  436.  
  437.                 cmp     word ptr es:[0],0AA55h  ;Branch if no signature is
  438.                 jne     next_block              ;found
  439.  
  440.                 mov     al,es:[2]               ;Get number of blocks
  441.                 cbw                             ;Convert byte to word
  442.                 mov     cl,9                    ;Compute length of adapter
  443.                 shl     ax,cl                   ;ROM in bytes
  444.                 mov     cx,ax                   ;Transfer result to CX
  445.                 xor     al,al                   ;Zero AL and DI
  446.                 xor     di,di
  447.  
  448. arom3:          add     al,es:[di]              ;Validate the ROM by summing
  449.                 inc     di                      ;all the bytes in it,
  450.                 loop    arom3                   ;modulo 100h
  451.                 or      al,al                   ;Not a valid ROM module if
  452.                 jnz     next_block              ;the result isn't zero
  453.  
  454.                 mov     al,es:[2]               ;Get number of blocks
  455.                 add     al,3                    ;Compute number of 2K
  456.                 shr     al,1                    ;blocks the module
  457.                 shr     al,1                    ;comprises
  458.                 mov     cl,al                   ;Transfer result to CL
  459.                 xor     ch,ch                   ;Byte to word in CX
  460.                 push    cx                      ;Save the result
  461.  
  462.                 mov     ax,cs                   ;Write "R"s to affected
  463.                 mov     es,ax                   ;areas of the MAP array
  464.                 mov     di,si
  465.                 add     di,offset map
  466.                 mov     al,"R"
  467.                 rep     stosb
  468.  
  469.                 pop     cx                      ;Retrieve block count
  470.                 add     si,cx                   ;Add block count to SI
  471.                 dec     si                      ;Decrement before proceeding
  472.  
  473. next_block:     cmp     si,168                  ;Increment SI and loop back
  474.                 jae     check_ram               ;if it's less than 168,
  475.                 inc     si                      ;which corresponds to
  476.                 jmp     arom1                   ;segment F400
  477. ;
  478. ; Check all 2K blocks that haven't been analyzed yet for ROM or RAM.
  479. ;
  480. check_ram:      call    disable_nmi             ;Disable NMI
  481.  
  482.                 xor     cx,cx                   ;Initialize counter
  483.                 mov     dx,cs                   ;DX holds segment address
  484.  
  485. ram1:           push    cx                              ;Save count
  486.                 mov     si,cx                           ;Transfer count to SI
  487.                 cmp     byte ptr [si+offset map],20h    ;Skip this block if
  488.                 je      ram2                            ;already checked
  489.                 jmp     next_region
  490.  
  491. ram2:           mov     cl,7                    ;Compute next segment address
  492.                 shl     si,cl                   ;by shifting SI 7 bits left
  493.                 add     si,0A000h               ;and adding A000h
  494.                 mov     bx,si                   ;Save result in BX
  495.  
  496.                 mov     ds,bx                   ;Copy the block to local
  497.                 assume  ds:nothing              ;memory
  498.                 xor     si,si
  499.                 mov     di,offset lastbyte
  500.                 mov     es,dx
  501.                 mov     cx,1024
  502.                 cli                             ;Interrupts off!!!
  503.                 rep     movsw
  504.                 mov     ds,dx
  505.                 assume  ds:code
  506.  
  507.                 mov     es,bx                   ;Copy test data to the
  508.                 xor     di,di                   ;block in upper memory
  509.                 mov     si,0100h
  510.                 mov     cx,1024
  511.                 rep     movsw
  512.  
  513.                 mov     ds,bx                   ;Copy the block to local
  514.                 assume  ds:nothing              ;memory again
  515.                 xor     si,si
  516.                 mov     di,offset lastbyte+2048
  517.                 mov     es,dx
  518.                 mov     cx,1024
  519.                 rep     movsw
  520.                 mov     ds,dx
  521.                 assume  ds:code
  522.  
  523.                 mov     es,bx                   ;Restore the block's
  524.                 xor     di,di                   ;original contents
  525.                 mov     si,offset lastbyte
  526.                 mov     cx,1024
  527.                 rep     movsw
  528.                 sti                             ;Interrupts on!!!
  529.  
  530.                 mov     si,0100h                ;Compare what was written
  531.                 mov     di,offset lastbyte+2048 ;to what was read back to
  532.                 mov     es,dx                   ;determine if this block
  533.                 mov     cx,1024                 ;is populated with RAM
  534.                 repe    cmpsw
  535.                 jne     ram3                    ;Branch if they're not equal
  536.  
  537.                 pop     si                      ;Retrieve count from stack
  538.                 push    si                      ;Push it back on for later
  539.                 mov     byte ptr [si+offset map],"+"    ;Mark block as RAM
  540.                 jmp     short next_region       ;Branch and continue
  541.  
  542. ram3:           mov     si,offset lastbyte      ;Compare the two sets of
  543.                 mov     di,offset lastbyte+2048 ;data read from the block
  544.                 mov     cx,1024                 ;to determine if the block
  545.                 repe    cmpsw                   ;is populated with ROM
  546.                 jne     ram4                    ;Branch if they're not equal
  547.  
  548.                 mov     di,offset lastbyte      ;See if all the bytes that
  549.                 mov     al,[di]                 ;were read have the same
  550.                 mov     cx,2048                 ;value. If they do, then
  551.                 repe    scasb                   ;this probably isn't ROM.
  552.                 je      next_region
  553.  
  554.                 pop     si                      ;Retrieve count from stack
  555.                 push    si                      ;Push it back on for later
  556.                 mov     byte ptr [si+offset map],"R"    ;Mark block as ROM
  557.                 jmp     short next_region       ;Branch and continue
  558.  
  559. ram4:           pop     si                      ;Retrieve count from stack
  560.                 push    si                      ;Push it back on for later
  561.                 mov     byte ptr [si+offset map],"U"    ;Mark block with "U"
  562.  
  563. next_region:    pop     cx                      ;Retrieve count
  564.                 inc     cx                      ;Increment count
  565.                 cmp     cx,192                  ;Loop until done
  566.                 je      build_exit
  567.                 jmp     ram1
  568.  
  569. build_exit:     call    enable_nmi              ;Enable NMI
  570.                 ret
  571. build_table     endp
  572.  
  573. ;****************************************************************************
  574. ; DISABLE_NMI disables NMI.
  575. ;****************************************************************************
  576.  
  577. disable_nmi     proc    near
  578.                 mov     ax,0C400h               ;Find out if this is a PS/2
  579.                 int     15h
  580.                 jc      dnmi1
  581.  
  582.                 xor     al,al                   ;Disable NMI on a PS/2
  583.                 out     70h,al
  584.                 jmp     short $+2
  585.                 jmp     short $+2
  586.                 in      al,71h
  587.                 jmp     short dnmi_exit
  588.  
  589. dnmi1:          in      al,0A0h                 ;Disable NMI on a non-
  590.                 jmp     short $+2               ;PS/2
  591.                 jmp     short $+2
  592.                 and     al,7Fh
  593.                 out     0A0h,al
  594. dnmi_exit:      ret
  595. disable_nmi     endp
  596.  
  597. ;****************************************************************************
  598. ; ENABLE_NMI enables NMI.
  599. ;****************************************************************************
  600.  
  601. enable_nmi      proc    near
  602.                 mov     ax,0C400h               ;Find out if this is a PS/2
  603.                 int     15h
  604.                 jc      enmi1
  605.  
  606.                 mov     al,80h                  ;Enable NMI on a PS/2
  607.                 out     70h,al
  608.                 jmp     short $+2
  609.                 jmp     short $+2
  610.                 in      al,71h
  611.                 jmp     short enmi_exit
  612.  
  613. enmi1:          in      al,0A0h                 ;Enable NMI on a non-
  614.                 jmp     short $+2               ;PS/2
  615.                 jmp     short $+2
  616.                 or      al,80h
  617.                 out     0A0h,al
  618. enmi_exit:      ret
  619. enable_nmi      endp
  620.  
  621. ;****************************************************************************
  622. ; DRAW_SCREEN paints the screen.
  623. ;****************************************************************************
  624.  
  625. draw_screen     proc    near
  626.                 call    clear_screen            ;Clear the screen
  627.  
  628.                 mov     ah,title_color          ;Write line 1 of the
  629.                 mov     dx,0012h                ;header at the top
  630.                 mov     si,offset header1       ;of the screen
  631.                 call    write_string
  632.  
  633.                 mov     ah,title_color          ;Write line 2 of the
  634.                 mov     dx,010Ch                ;header
  635.                 mov     si,offset header2
  636.                 call    write_string
  637.  
  638.                 mov     ah,border_color         ;Draw the border around
  639.                 mov     cx,0300h                ;the window at the top
  640.                 mov     dx,104Fh                ;of the screen
  641.                 call    drawbox
  642.  
  643.                 mov     ax,0600h                ;Clear the interior of
  644.                 mov     bh,back_color           ;the window
  645.                 mov     cx,0401h
  646.                 mov     dx,0F4Eh
  647.                 int     10h
  648.  
  649.                 mov     ax,0600h                ;Draw the shadow behind
  650.                 mov     bh,shadow_color         ;the first subwindow
  651.                 mov     cx,0605h
  652.                 mov     dx,0E2Eh
  653.                 int     10h
  654.  
  655.                 mov     ax,0600h                ;Draw the shadow behind
  656.                 mov     bh,shadow_color         ;the second subwindow
  657.                 mov     cx,0635h
  658.                 mov     dx,0E4Bh
  659.                 int     10h
  660.  
  661.                 mov     ax,0600h                ;Draw the first subwindow
  662.                 mov     bh,fore_color
  663.                 mov     cx,0504h
  664.                 mov     dx,0D2Dh
  665.                 int     10h
  666.  
  667.                 mov     ax,0600h                ;Draw the second subwindow
  668.                 mov     bh,fore_color
  669.                 mov     cx,0534h
  670.                 mov     dx,0D4Ah
  671.                 int     10h
  672.  
  673.                 mov     ah,fore_color           ;Display segment addresses
  674.                 mov     dx,0705h
  675.                 mov     si,offset text1
  676.                 call    write_string
  677.  
  678.                 mov     ah,fore_color
  679.                 mov     dx,0805h
  680.                 mov     si,offset text2
  681.                 call    write_string
  682.  
  683.                 mov     ah,fore_color
  684.                 mov     dx,0905h
  685.                 mov     si,offset text3
  686.                 call    write_string
  687.  
  688.                 mov     ah,fore_color
  689.                 mov     dx,0A05h
  690.                 mov     si,offset text4
  691.                 call    write_string
  692.  
  693.                 mov     ah,fore_color
  694.                 mov     dx,0B05h
  695.                 mov     si,offset text5
  696.                 call    write_string
  697.  
  698.                 mov     ah,fore_color
  699.                 mov     dx,0C05h
  700.                 mov     si,offset text6
  701.                 call    write_string
  702.  
  703.                 mov     si,offset text7         ;Display "0" thru "F"
  704.                 mov     cx,16                   ;above the first
  705. dscr1:          push    cx                      ;subwindow
  706.                 lodsb
  707.                 mov     dl,al
  708.                 mov     dh,06h
  709.                 lodsb
  710.                 mov     ah,fore_color
  711.                 call    write_char
  712.                 pop     cx
  713.                 loop    dscr1
  714.  
  715.                 mov     ah,rom_color            ;Display "LEGEND"
  716.                 mov     dx,0635h
  717.                 mov     si,offset text8
  718.                 call    write_string
  719.  
  720.                 mov     ah,rom_color            ;Display legend labels
  721.                 mov     dx,0835h
  722.                 mov     si,offset text9
  723.                 call    write_string
  724.  
  725.                 mov     ah,ram_color
  726.                 mov     dx,0935h
  727.                 mov     si,offset text10
  728.                 call    write_string
  729.  
  730.                 mov     ah,video_color
  731.                 mov     dx,0A35h
  732.                 mov     si,offset text11
  733.                 call    write_string
  734.  
  735.                 mov     ah,ems_color
  736.                 mov     dx,0B35h
  737.                 mov     si,offset text12
  738.                 call    write_string
  739.  
  740.                 mov     ah,unk_color
  741.                 mov     dx,0C35h
  742.                 mov     si,offset text12x
  743.                 call    write_string
  744.  
  745.                 mov     ah,fore_color           ;Display legend notes
  746.                 mov     dx,083Bh
  747.                 mov     si,offset text13
  748.                 call    write_string
  749.  
  750.                 mov     ah,fore_color
  751.                 mov     dx,093Bh
  752.                 mov     si,offset text14
  753.                 call    write_string
  754.  
  755.                 mov     ah,fore_color
  756.                 mov     dx,0A3Bh
  757.                 mov     si,offset text15
  758.                 call    write_string
  759.  
  760.                 mov     ah,fore_color
  761.                 mov     dx,0B3Bh
  762.                 mov     si,offset text16
  763.                 call    write_string
  764.  
  765.                 mov     ah,fore_color
  766.                 mov     dx,0C3Bh
  767.                 mov     si,offset text17
  768.                 call    write_string
  769.  
  770.                 mov     ah,note_color           ;Display notes at the
  771.                 mov     dx,1200h                ;bottom of the screen
  772.                 mov     si,offset text18
  773.                 call    write_string
  774.  
  775.                 mov     ah,note_color
  776.                 mov     dx,1300h
  777.                 mov     si,offset text19
  778.                 call    write_string
  779.  
  780.                 mov     ah,note_color
  781.                 mov     dx,1400h
  782.                 mov     si,offset text20
  783.                 call    write_string
  784.  
  785.                 mov     ah,note_color
  786.                 mov     dx,1500h
  787.                 mov     si,offset text21
  788.                 call    write_string
  789.  
  790.                 mov     ah,note_color
  791.                 mov     dx,1600h
  792.                 mov     si,offset text22
  793.                 call    write_string
  794.  
  795.                 mov     ah,rom_color            ;Highlight text in the
  796.                 mov     dx,1203h                ;notes area
  797.                 mov     si,offset text9
  798.                 call    write_string
  799.  
  800.                 mov     ah,ram_color
  801.                 mov     dx,1303h
  802.                 mov     si,offset text10
  803.                 call    write_string
  804.  
  805.                 mov     ah,unk_color
  806.                 mov     dx,1410h
  807.                 mov     si,offset text12x
  808.                 call    write_string
  809.  
  810.                 mov     ah,title_color          ;Display "Press Esc to
  811.                 mov     dx,181Eh                ;exit"
  812.                 mov     si,offset text23
  813.                 call    write_string
  814.                 ret
  815. draw_screen     endp
  816.  
  817. ;****************************************************************************
  818. ; DRAW_MAP draws the memory map stored in the MAP array.
  819. ;****************************************************************************
  820.  
  821. draw_map        proc    near
  822.                 mov     dx,0C0Ah                ;Initialize DX
  823.                 mov     si,offset map           ;Point SI to MAP array
  824.  
  825.                 mov     cx,6                    ;Do six rows, saving CX and
  826. dmap1:          push    cx                      ;and DX prior to each pass
  827.                 push    dx                      ;through the loop
  828.  
  829.                 mov     cx,4                    ;Do four sets of columns in
  830. dmap2:          push    cx                      ;each row, each time saving
  831.                 push    dx                      ;CX and DX at the beginning
  832.  
  833.                 mov     cx,8                    ;Eight characters per set
  834. dmap3:          push    cx                      ;Save CX and DX
  835.                 push    dx
  836.                 lodsb                           ;Get the MAP character
  837.  
  838.                 mov     ah,fore_color           ;Load the appropriate video
  839.                 cmp     al,"R"                  ;attribute in AH
  840.                 jne     dmap4
  841.                 mov     ah,rom_color
  842.                 jmp     short dmap8
  843.  
  844. dmap4:          cmp     al,"+"
  845.                 jne     dmap5
  846.                 mov     ah,ram_color
  847.                 jmp     short dmap8
  848.  
  849. dmap5:          cmp     al,"V"
  850.                 jne     dmap6
  851.                 mov     ah,video_color
  852.                 jmp     short dmap8
  853.  
  854. dmap6:          cmp     al,"E"
  855.                 jne     dmap7
  856.                 mov     ah,ems_color
  857.                 jmp     short dmap8
  858.  
  859. dmap7:          cmp     al,"U"
  860.                 jne     dmap8
  861.                 mov     ah,unk_color
  862.  
  863. dmap8:          call    write_char              ;Output the character
  864.                 pop     dx                      ;Retrieve row and column
  865.                 inc     dl                      ;Increment the column number
  866.                 pop     cx                      ;Retrieve count in CX
  867.                 loop    dmap3                   ;Loop until done
  868.  
  869.                 pop     dx                      ;Retrieve row and column
  870.                 add     dl,9                    ;Add 9 to the column number
  871.                 pop     cx                      ;Retrieve set count in CX
  872.                 loop    dmap2                   ;Loop until done
  873.  
  874.                 pop     dx                      ;Retrieve row and column
  875.                 dec     dh                      ;Decrement the row number
  876.                 mov     dl,0Ah                  ;Reinitialize column number
  877.                 pop     cx                      ;Retrieve row count in CX
  878.                 loop    dmap1                   ;Loop until done
  879.                 ret
  880. draw_map        endp
  881.  
  882. ;****************************************************************************
  883. ; TEST_CRTC tests for the presence of a 6845-style CRT controller at the
  884. ; port address specified in DX. On return, carry is clear if a CRTC was
  885. ; detected, or set if no CRTC was found.
  886. ;****************************************************************************
  887.  
  888. test_crtc       proc    near
  889.                 mov     al,0Fh                  ;Set CRTC address register to
  890.                 out     dx,al                   ;0Fh (Cursor Address Low)
  891.                 jmp     short $+2               ;I/O delay
  892.                 jmp     short $+2
  893.  
  894.                 inc     dx                      ;Point DX to data register
  895.                 in      al,dx                   ;Read Cursor Address Low
  896.                 mov     ah,al                   ;Save result in AH
  897.                 not     al                      ;Flip the bits in AL
  898.                 mov     bl,al                   ;Save this result in BL
  899.                 out     dx,al                   ;Write the new value back
  900.                 jmp     short $+2               ;I/O delay
  901.                 jmp     short $+2
  902.  
  903.                 in      al,dx                   ;Read Cursor Address Low
  904.                 jmp     short $+2               ;I/O delay
  905.                 jmp     short $+2
  906.                 xchg    al,ah                   ;Swap AH and AL
  907.                 out     dx,al                   ;Restore original value
  908.                 cmp     ah,bl                   ;No CRTC here is AH is not
  909.                 jne     test1                   ;equal to BL
  910.  
  911.                 clc                             ;Clear the carry flag
  912.                 ret                             ;and return
  913.  
  914. test1:          stc                             ;Set the carry flag
  915.                 ret                             ;and return
  916. test_crtc       endp
  917.  
  918. ;****************************************************************************
  919. ; CLEAR_SCREEN clears the screen. Set MAXROW equal to the number of rows
  920. ; displayed minus 1 before calling this procedure.
  921. ;****************************************************************************
  922.  
  923. clear_screen    proc    near
  924.                 mov     ax,0600h
  925.                 mov     bh,07h
  926.                 mov     cx,0000h
  927.                 mov     dh,maxrow
  928.                 mov     dl,4Fh
  929.                 int     10h
  930.                 ret
  931. clear_screen    endp
  932.  
  933. ;****************************************************************************
  934. ; DRAWBOX draws a box in text mode using single-line graphics characters.
  935. ; On entry, CX holds the row and column address of the upper left corner,
  936. ; and DX holds the row and column address of the lower right corner. AH
  937. ; holds the video attribute used to draw the box.
  938. ;****************************************************************************
  939.  
  940. rows            dw      0                       ;Number of rows
  941. columns         dw      0                       ;Number of columns
  942.  
  943. drawbox         proc    near
  944.                 sub     dh,ch                   ;Compute the number of rows
  945.                 dec     dh                      ;inside the box
  946.                 mov     byte ptr rows,dh
  947.                 sub     dl,cl                   ;Then compute the number of
  948.                 dec     dl                      ;columns
  949.                 mov     byte ptr columns,dl
  950.  
  951.                 push    ax                      ;Save video attribute
  952.                 mov     dx,cx                   ;Place starting address in DX
  953.                 call    compute_address         ;Compute the memory address
  954.                 mov     di,ax                   ;Transfer result to DI
  955.                 mov     es,video_segment        ;Point ES to the video buffer
  956.                 pop     ax                      ;Retrieve video attribute
  957.                 push    di                      ;Save video buffer address
  958.  
  959.                 mov     al,0DAh                 ;Draw the upper left corner
  960.                 stosw                           ;of the box
  961.                 mov     al,0C4h                 ;Draw the upper horizontal
  962.                 mov     cx,columns
  963.                 rep     stosw
  964.                 mov     al,0BFh                 ;Draw the upper right corner
  965.                 stosw                           ;of the box
  966.  
  967.                 sub     di,2                    ;Point DI to the end of the
  968.                 add     di,line_length          ;second row of the box
  969.                 mov     cx,rows                 ;Draw right vertical
  970.                 call    draw_vertical
  971.                 mov     al,0D9h                 ;Draw the lower right corner
  972.                 stosw                           ;of the box
  973.  
  974.                 pop     di                      ;Retrieve address
  975.                 add     di,line_length          ;Point DI to the second row
  976.                 mov     cx,rows                 ;Draw left vertical
  977.                 call    draw_vertical
  978.                 mov     al,0C0h                 ;Draw the lower left corner
  979.                 stosw                           ;of the box
  980.  
  981.                 mov     al,0C4h                 ;Draw the lower horizontal
  982.                 mov     cx,columns
  983.                 rep     stosw
  984.                 ret
  985. drawbox         endp
  986.  
  987. ;****************************************************************************
  988. ; DRAW_VERTICAL draws a vertical line. On entry, ES:DI points to the
  989. ; location in the video buffer, AH holds the video attribute, and CX
  990. ; holds the length of the line in rows.
  991. ;****************************************************************************
  992.  
  993. draw_vertical   proc    near
  994.                 mov     al,0B3h                 ;Load AL with ASCII code
  995. dv_loop:        stosw                           ;Write one character
  996.                 sub     di,2                    ;Point DI to the character
  997.                 add     di,line_length          ;cell on the next row
  998.                 loop    dv_loop                 ;Loop until done
  999.                 ret
  1000. draw_vertical   endp
  1001.  
  1002. ;****************************************************************************
  1003. ; WRITE_STRING writes an ASCIIZ string at the row and column address
  1004. ; specified in DH and DL. On entry, AH contains the video attribute and
  1005. ; DS:SI points to the string.
  1006. ;****************************************************************************
  1007.  
  1008. write_string    proc    near
  1009.                 push    ax                      ;Save video attribute
  1010.                 call    compute_address         ;Compute the memory address
  1011.                 mov     di,ax                   ;Transfer result to DI
  1012.                 mov     es,video_segment        ;Point ES to the video buffer
  1013.                 pop     ax                      ;Retrieve video attribute
  1014.  
  1015. ws_loop:        lodsb                           ;Get a character
  1016.                 or      al,al                   ;Exit if it's zero
  1017.                 jz      ws_exit
  1018.                 stosw                           ;Display it
  1019.                 jmp     ws_loop                 ;Loop back for more
  1020. ws_exit:        ret
  1021. write_string    endp
  1022.  
  1023. ;****************************************************************************
  1024. ; WRITE_CHAR writes a character and attribute at the row and column
  1025. ; address specified in DH and DL. On entry, AH holds the video attribute
  1026. ; and AL holds the character's ASCII code.
  1027. ;****************************************************************************
  1028.  
  1029. write_char      proc    near
  1030.                 push    ax                      ;Save video attribute
  1031.                 call    compute_address         ;Compute the memory address
  1032.                 mov     di,ax                   ;Transfer result to DI
  1033.                 mov     es,video_segment        ;Point ES to the video buffer
  1034.                 pop     ax                      ;Retrieve video attribute
  1035.                 stosw                           ;Write the character and
  1036.                 ret                             ;attribute and exit
  1037. write_char      endp
  1038.  
  1039. ;****************************************************************************
  1040. ; COMPUTE_ADDRESS returns in AX the video buffer address that corresponds
  1041. ; to the row and column number passed in DH and DL. Before this procedure
  1042. ; is called, LINE_LENGTH must contain the number of bytes per video line
  1043. ; and VIDEO_OFFSET must contain the offset within the video buffer of the
  1044. ; current video page.
  1045. ;****************************************************************************
  1046.  
  1047. compute_address proc    near
  1048.                 mov     cl,dl                   ;Save DL in CL
  1049.                 mov     al,dh                   ;Get starting row in AL
  1050.                 cbw                             ;Convert byte to word in AX
  1051.                 mul     line_length             ;Multiply by bytes per row
  1052.                 mov     dl,cl                   ;Load DL with column number
  1053.                 shl     dx,1                    ;Multiply starting column by 2
  1054.                 add     ax,dx                   ;Add it to AX
  1055.                 add     ax,video_offset         ;Add video buffer offset
  1056.                 ret
  1057. compute_address endp
  1058.  
  1059. lastbyte        label   byte
  1060.  
  1061. code            ends
  1062.                 end     begin
  1063.